package cn.com.anysdk.oss.monitor;

import cn.com.anysdk.oss.api.OssExceptionListener;
import cn.com.anysdk.oss.exception.OssException;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * OSS 监控管理器
 * 用于管理异常监听器和收集操作指标
 */
@Slf4j
public class OssMonitorManager {
    private static final OssMonitorManager INSTANCE = new OssMonitorManager();

    private final List<OssExceptionListener> listeners = new ArrayList<>();
    private final Map<String, AtomicLong> operationCounters = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> errorCounters = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> durationMetrics = new ConcurrentHashMap<>();

    private OssMonitorManager() {}

    public static OssMonitorManager getInstance() {
        return INSTANCE;
    }

    /**
     * 添加异常监听器
     * @param listener 异常监听器
     */
    public void addListener(OssExceptionListener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }

    /**
     * 移除异常监听器
     * @param listener 异常监听器
     */
    public void removeListener(OssExceptionListener listener) {
        if (listener != null) {
            listeners.remove(listener);
        }
    }

    /**
     * 通知所有监听器
     * @param exception 异常信息
     * @param context 操作上下文
     */
    public void notifyListeners(OssException exception, OssOperationContext context) {
        for (OssExceptionListener listener : listeners) {
            try {
                listener.onException(exception, context);
            } catch (Exception e) {
                log.error("Error notifying listener: " + e.getMessage(), e);
            }
        }
    }

    /**
     * 处理异常
     * @param exception 异常信息
     * @param context 操作上下文
     */
    public void handleException(OssException exception, OssOperationContext context) {
        // 记录错误计数
        String operationKey = String.format("%s_%s", context.getProvider(), context.getOperationType());
        errorCounters.computeIfAbsent(operationKey, k -> new AtomicLong()).incrementAndGet();

        // 通知监听器
        notifyListeners(exception, context);
    }

    /**
     * 记录操作开始
     */
    public void recordOperationStart(OssOperationContext context) {
        String operationKey = String.format("%s_%s", context.getProvider(), context.getOperationType());
        operationCounters.computeIfAbsent(operationKey, k -> new AtomicLong()).incrementAndGet();
    }

    /**
     * 记录操作结束
     */
    public void recordOperationEnd(OssOperationContext context) {
        String operationKey = String.format("%s_%s", context.getProvider(), context.getOperationType());
        durationMetrics.computeIfAbsent(operationKey, k -> new AtomicLong())
                      .addAndGet(context.getDuration());
    }

    /**
     * 获取操作计数
     */
    public long getOperationCount(String provider, OssOperationContext.OperationType type) {
        String key = String.format("%s_%s", provider, type);
        AtomicLong counter = operationCounters.get(key);
        return counter != null ? counter.get() : 0;
    }

    /**
     * 获取错误计数
     */
    public long getErrorCount(String provider, OssOperationContext.OperationType type) {
        String key = String.format("%s_%s", provider, type);
        AtomicLong counter = errorCounters.get(key);
        return counter != null ? counter.get() : 0;
    }

    /**
     * 获取平均操作时间
     */
    public double getAverageOperationDuration(String provider, OssOperationContext.OperationType type) {
        String key = String.format("%s_%s", provider, type);
        AtomicLong totalDuration = durationMetrics.get(key);
        AtomicLong totalCount = operationCounters.get(key);

        if (totalDuration != null && totalCount != null && totalCount.get() > 0) {
            return (double) totalDuration.get() / totalCount.get();
        }
        return 0.0;
    }

    /**
     * 重置所有计数器
     */
    public void resetMetrics() {
        operationCounters.clear();
        errorCounters.clear();
        durationMetrics.clear();
    }
}